package nave.model;

import java.util.Random;

import nave.Point;

/**
 * @author henrique
 * 
 * @date August / 2011
 */
public final class Stage {
	
	/*
	 * Attributes
	 */
	private static int stage[][];
	private static Random randomGenerator = new Random();
	
	/*
	 * Constants
	 */
	public final static int STAGES_RANDOM = 0;
	public final static int STAGES_CAMPAIGN = 1;
	
	/*
	 * Constructor
	 */
	public Stage(int rows, int cols, int stageType) {		
		
		Stage.stage = new int[rows][cols];
		
		nextStage(stageType);
	}

	/*
	 * Public methods
	 */
	public static void nextStage(int stageType) {
		
		if ( stageType == STAGES_RANDOM )
			Stage.generate();
		
		else if ( stageType == STAGES_CAMPAIGN )
			Stage.getNextCampaignStage();
	}

	public static int getPositionOnStage(int i, int j) {
		try
		{
			return stage[i][j];
		}
		catch( ArrayIndexOutOfBoundsException e )
		{
			return nave.Constants.WALL;
		}
	}
	public static int getPositionOnStage(Point position) {
		return getPositionOnStage(position.y, position.x);
	}
	
	public static void setPositionOnStage(int i, int j, int value) {
		try
		{
			Stage.stage[i][j] = value;
		}
		catch( ArrayIndexOutOfBoundsException e ){}
	}
	public static void setPositionOnStage(Point position, int value) {
		setPositionOnStage(position.y, position.x, value);
	}

	public static int getCols() {
		return stage[0].length;
	}
	public static int getRows() {
		return stage.length;
	}

	/*
	 * Private methods
	 */
	private static void generate() {
		// clean border
		for( int i = 1; i < getRows()-1; i++ )
		{
			setPositionOnStage(i, 0, nave.Constants.EMPTY);
			setPositionOnStage(i, getCols()-1, nave.Constants.EMPTY);
		}
		for( int i = 1; i < getCols()-1; i++ )
		{
			setPositionOnStage(0, i, nave.Constants.EMPTY);
			setPositionOnStage(getRows()-1, i, nave.Constants.EMPTY);
		}
		
		// generate randomly the stage 
		for( int i = 1; i < getRows()-1; i++ )
		{
			for( int j = 1; j < getCols()-1; j++ )
			{
				if ( randomGenerator.nextBoolean() )
				{
					setPositionOnStage(i, j, nave.Constants.WALL);
				}
				else
				{
					setPositionOnStage(i, j, nave.Constants.EMPTY);
				}
			}
		}
		
		// make it possible to walk through all the stage
		continuos();
	}
	private static void continuos() {
		int di, dj, aux, up, down, left, right;

        for(int i = 1; i < getRows()-1; i++)
        {
        	for(int j = 1; j < getCols()-1; j++)
        	{
        		if( stage[i][j] == nave.Constants.EMPTY )
        		{
                    up = down = left = right = 0;
    
                // count empty spaces from this point
	                if( getPositionOnStage(i-1, j) == nave.Constants.EMPTY )
	                    up = 1;
	                if( getPositionOnStage(i+1, j) == nave.Constants.EMPTY )
	                    down = 1;
	                if( getPositionOnStage(i, j-1) == nave.Constants.EMPTY )
	                    left = 1;
	                if( getPositionOnStage(i, j+1) == nave.Constants.EMPTY )
	                    right = 1;

	            // if there is more than two, go to next
	                if( up + down + left + right > 2)
	                    continue;

	            // if there is no empty space, open one 
	                if( up + down + left + right == 0 ) {
	                    aux = randomGenerator.nextInt(4);
	                    di = i;
	                    dj = j;

	                    if (aux == 0) {
	                    	di++;
	                    	down = 1;
	                    }
	                    else if (aux == 1) {
	                    	di--;
	                    	up = 1;
	                    }
	                    else if (aux == 2) {
	                    	dj++;
	                    	right = 1;
	                    }
	                    else if (aux == 3) {
	                    	dj--;
	                    	left = 1;
	                    }

	                    setPositionOnStage(di, dj, nave.Constants.EMPTY);
	                }

                // if there is only one open, opens the opposite side
	                if( up + down + left + right == nave.Constants.WALL ) {
	                    if( stage[i-1][j] == nave.Constants.EMPTY )
	                    	setPositionOnStage(i+1, j, nave.Constants.EMPTY);
	                    if( stage[i+1][j] == nave.Constants.EMPTY )
	                    	setPositionOnStage(i-1, j, nave.Constants.EMPTY);
	                    if( stage[i][j-1] == nave.Constants.EMPTY )
	                    	setPositionOnStage(i, j+1, nave.Constants.EMPTY);
	                    if( stage[i][j+1] == nave.Constants.EMPTY )
	                    	setPositionOnStage(i, j-1, nave.Constants.EMPTY);
	                }
	                
                // if there is only two...
	                if( up + down + left + right == 2) {
	                	aux = randomGenerator.nextInt(2);
	                	// check if those two form an right angle
	                	// if so, it closes one of them
	                	// and opens the opposite of the left one
	                    if( up + left == 2 ) {
	                        if(aux == 1) {
	                        	setPositionOnStage(i-1, j, nave.Constants.WALL);
	                        	setPositionOnStage(i, j+1, nave.Constants.EMPTY);
	                        }
	                        else {
	                        	setPositionOnStage(i, j-1, nave.Constants.WALL);
	                        	setPositionOnStage(i+1, j, nave.Constants.EMPTY);
	                        }
	                    }
	                    else if( left + down == 2 ) {
	                        if(aux == 1) {
	                        	setPositionOnStage(i, j-1, nave.Constants.WALL);
	                        	setPositionOnStage(i-1, j, nave.Constants.EMPTY);
	                        } else {
	                        	setPositionOnStage(i+1, j, nave.Constants.WALL);
	                        	setPositionOnStage(i, j+1, nave.Constants.EMPTY);
	                        }
	                    }
	                    else if( down + right == 2 ) {
	                        if(aux == 1) {
	                        	setPositionOnStage(i+1, j, nave.Constants.WALL);
	                        	setPositionOnStage(i, j-1, nave.Constants.EMPTY);
	                        } else {
	                        	setPositionOnStage(i, j+1, nave.Constants.WALL);
	                        	setPositionOnStage(i-1, j, nave.Constants.EMPTY);
	                        }
	                    }
	                    else if( right + up == 2 ) {
	                        if(aux == 1) {
	                        	setPositionOnStage(i, j+1, nave.Constants.WALL);
	                            setPositionOnStage(i+1, j, nave.Constants.EMPTY);
	                        } else {
	                        	setPositionOnStage(i-1, j, nave.Constants.WALL);
	                        	setPositionOnStage(i, j-1, nave.Constants.EMPTY);
	                        }
	                    }
	                }
	            }
	        }
	    }
	}
	private static void getNextCampaignStage() {
		// TODO Auto-generated method stub
	}

	// TODO debug only
	public static String print() {
		String result = "";
		
		for( int i = 0; i < getRows(); i++ )
		{
			for( int j = 0; j < getCols(); j++ )
			{
				result = result + getPositionOnStage(i, j) + "  ";
			}
			result = result + "\n";
		}
		return result;
	}
}
